/*
 * CommunicationDespacho.cpp
 *
 */

#include "../logger/logger.h"
#include "CommunicationDespacho.h"
#include "../capa_servicios_distribuidos/QueueLauncher.h"
#include "../channel_common/agent_address_service/AgentAddressService.h"

namespace middleware {

const Uid CommunicationDespacho::UIDDespachoRequest = "despachoRequest";
const Uid CommunicationDespacho::UIDDespachoReply = "despachoReply";
const Uid CommunicationDespacho::UIDEntrega = "despachoEntrega";

CommunicationDespacho::CommunicationDespacho(std::string hostName)
					:m_RequestQueue(ipc::MessageQueue<DespachoRequestStruct>::
						get(IPCUids::getFile(UIDDespachoRequest)+hostName,IPCUids::getKey(UIDDespachoRequest))),
					m_ReplyQueue(ipc::MessageQueue<DespachoReplyStruct>::
						get(IPCUids::getFile(UIDDespachoReply)+hostName,IPCUids::getKey(UIDDespachoReply))),
					m_EntregaQueue(ipc::MessageQueue<EntregaProductoStruct>::
						get(IPCUids::getFile(UIDEntrega)+hostName,IPCUids::getKey(UIDEntrega)))
{
	m_mTypeRequest= channel::AgentAddressService::resolve("despacho_req");
}

CommunicationDespacho::~CommunicationDespacho() {
}

void CommunicationDespacho::getDespachoRequest(DespachoRequestType &reqType,
													OrdenCompraHeader &ordenCompra,
													ProductoCantidad &producto)

{
	DespachoRequestStruct request;

//	CLogger::log("Mtype request obtenido:"+StringUtils::NumberToString(m_mTypeRequest),
//							LogLevelEnum::TRACE);

	request = m_RequestQueue.get(m_mTypeRequest);

	reqType = request.requestType;
	ordenCompra = request.ordenCompra;
	producto = request.producto;
}

void CommunicationDespacho::notificarDespachoOCLista(
		OrdenCompraHeader& ordenCompra, ProductoCantidad& producto)
{
	DespachoRequestStruct request;

	request.producto = producto;
	request.requestType = NOTIFICAR_DESPACHO;
	request.ordenCompra = ordenCompra;

	m_RequestQueue.put(m_mTypeRequest,request);
}

void CommunicationDespacho::esperarNotificacion(int clientId)
{
	DespachoReplyStruct reply;

	CLogger::log("El cliente:"+StringUtils::NumberToString(clientId)+ " espera una notificacion",
								LogLevelEnum::TRACE);

	reply = m_ReplyQueue.get(clientId);

	if(reply.replyType != NOTIFICACION_CLIENTE)
		throw Exception("Notificacion de tipo incorrecto recibida");
}

void CommunicationDespacho::retirarProducto(OrdenCompraHeader& ordenCompra,
												  TipoProducto& tipoProducto,
												  Producto &producto)
{
	DespachoRequestStruct request;
	EntregaProductoStruct reply;

	request.producto.tipo = tipoProducto;
	request.requestType = RETIRAR;
	request.ordenCompra = ordenCompra;

	m_RequestQueue.put(m_mTypeRequest,request);
	reply = m_EntregaQueue.get(ordenCompra.clientId);

	producto = reply.producto;
}

void CommunicationDespacho::notificarCliente(OrdenCompraHeader &ordenCompra,
												   ProductoCantidad &producto)
{
	DespachoReplyStruct reply;

	reply.replyType = NOTIFICACION_CLIENTE;
	reply.producto = producto;
	reply.ordenCompra = ordenCompra;

	CLogger::log("Se notifica al cliente:"+StringUtils::NumberToString(ordenCompra.clientId)+ " que el pedido esta completo.",
										LogLevelEnum::TRACE);

	m_ReplyQueue.put(ordenCompra.clientId,reply);
}

void CommunicationDespacho::entregarProducto(OrdenCompraHeader& ordenCompra, Producto& producto)
{
	EntregaProductoStruct request;
	request.producto = producto;
	request.ordenCompra = ordenCompra;

	m_EntregaQueue.put(ordenCompra.clientId,request);
}

void CommunicationDespacho::launchForClient(std::string hostName, int clientId)
{
	servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
		<DespachoReplyStruct>(
		UIDDespachoReply,hostName,servicios_distribuidos::QUEUE_RECV,clientId);

	servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
				<EntregaProductoStruct>(
				UIDEntrega,	hostName,
				servicios_distribuidos::QUEUE_RECV,clientId);

}

void CommunicationDespacho::create(DespachoCommunicationType type, std::string hostName)
{
	int mtypeDespachoReq = channel::AgentAddressService::registerNameStatic("despacho_req",0);

	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
	<DespachoRequestStruct>(
		UIDDespachoRequest,	hostName,
		(type == SIDE_DESPACHO) ? servicios_distribuidos::QUEUE_RECV : servicios_distribuidos::QUEUE_SEND,
		mtypeDespachoReq);


	if(type!=CLIENTE)
	{
		servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
			<DespachoReplyStruct>(
			UIDDespachoReply,hostName,
			servicios_distribuidos::QUEUE_SEND);

		servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
					<EntregaProductoStruct>(
					UIDEntrega,	hostName,
					servicios_distribuidos::QUEUE_SEND);
	}
	else
	{
		ipc::MessageQueue<DespachoReplyStruct>::
			create(IPCUids::getFile(UIDDespachoReply)+hostName,
					IPCUids::getKey(UIDDespachoReply));

		ipc::MessageQueue<EntregaProductoStruct>::
			create(IPCUids::getFile(UIDEntrega)+hostName,
					IPCUids::getKey(UIDEntrega));
	}

}

void CommunicationDespacho::destroy(DespachoCommunicationType type, std::string hostName)
{

	ipc::MessageQueue<DespachoRequestStruct>::destroy(IPCUids::getFile(UIDDespachoRequest)+hostName,IPCUids::getKey(UIDDespachoRequest));
	ipc::MessageQueue<DespachoReplyStruct>::destroy(IPCUids::getFile(UIDDespachoReply)+hostName,IPCUids::getKey(UIDDespachoReply));
	ipc::MessageQueue<EntregaProductoStruct>::destroy(IPCUids::getFile(UIDEntrega)+hostName,IPCUids::getKey(UIDEntrega));
}

} /* namespace middleware */
